import socket
import time

def _get_currently_active_task():
    # TODO: nasty code (but can we avoid the circular dependency?)
    from tasks import TaskManager as _TaskManager
    return _TaskManager.get_instance().currently_active_task()


class AbstractEvent(object):
    """Abstract base class for any event"""
    
    task = property(lambda self: self.__task)
    timestamp = property(lambda self: self.__timestamp)
    content = property(lambda self: self.__content)
    
    def __init__(self, content):
        self.__task = _get_currently_active_task()
        self.__timestamp = time.time()
        self.__content = content


class InformationEvent(AbstractEvent):

    def __init__(self, information):
        super(InformationEvent, self).__init__( information )


class WarningEvent(AbstractEvent):

    def __init__(self, warning):
        super(WarningEvent, self).__init__( warning )


class ErrorEvent(AbstractEvent):

    exception_info = property(lambda self: self.__exception_info)
    
    def __init__(self, exception_info):
        super(ErrorEvent, self).__init__( exception_info[1] )
        self.__exception_info = exception_info


class FatalEvent(AbstractEvent):

    exception_info = property(lambda self: self.__exception_info)

    def __init__(self, exception_info):
        super(FatalEvent, self).__init__( exception_info[1] )
        self.__exception_info = exception_info


class RollbackBeganEvent(AbstractEvent):
    
    def __init__(self):
        super(RollbackBeganEvent, self).__init__( "rollback began" )


class RollbackFinishedEvent(AbstractEvent):
    
    def __init__(self):
        super(RollbackFinishedEvent, self).__init__( "rollback finished" )


class TaskBeganEvent(AbstractEvent):
    
    task_name = property(lambda self: self.__task_name)

    def __init__(self, task_name):
        super(TaskBeganEvent, self).__init__( "'%s' task started" % task_name)
        self.__task_name = task_name


class TaskFinishedEvent(AbstractEvent):
    
    task_name = property(lambda self: self.__task_name)

    def __init__(self, task_name):
        super(TaskFinishedEvent, self).__init__( "'%s' task finished" % task_name)
        self.__task_name = task_name


class AbstractUserEvent(AbstractEvent):
    """Abstract base class for any event that specifically
    applies to a User"""

    user = property(lambda self: self.__user)

    def __init__(self, content, user):
        super(AbstractUserEvent, self).__init__( content )
        self.__user = user


class UserErrorEvent(AbstractUserEvent):

    exception_info = property(lambda self: self.__exception_info)

    def __init__(self, exception_info, user):
        super(UserErrorEvent, self).__init__(exception_info[1], user)
        self.__exception_info = exception_info


class ShellCommandEvent(AbstractUserEvent):
    
    def __init__(self, command, user):
        super(ShellCommandEvent, self).__init__(command, user)


class StdoutEvent(AbstractUserEvent):

    def __init__(self, line, user):
        super(StdoutEvent, self).__init__(line, user)
        

class StderrEvent(AbstractUserEvent):

    def __init__(self, line, user):
        super(StderrEvent, self).__init__(line, user)


class StdinEvent(AbstractUserEvent):

    def __init__(self, line, user):
        super(StdinEvent, self).__init__(line, user)


class PullEvent(AbstractUserEvent):

    local_filename = property(lambda self: self.__local_filename)
    remote_filename = property(lambda self: self.__remote_filename)

    def __init__(self, local_filename, remote_filename, user):
        content = "pulling file '%s' from local file '%s'" % (remote_filename, local_filename)
        super(PullEvent, self).__init__(content, user)
        self.__local_filename = local_filename
        self.__remote_filename = remote_filename


class MkdirEvent(AbstractUserEvent):
    
    remote_dir = property(lambda self: self.__remote_dir)

    def __init__(self, remote_dir, user):
        content = "making directory '%s'" % remote_dir
        super(MkdirEvent, self).__init__(content, user)
        self.__remote_dir = remote_dir
